/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skybash;

import java.util.ArrayList;
import java.util.HashMap;
import lev.Ln;
import skyproc.*;
import skyproc.BodyTemplate.BodyPart;
import skyproc.BodyTemplate.BodyTemplateFlag;
import skyproc.gui.SPProgressBarPlug;

/**
 *
 * @author pc tech
 */
public class RaceMergerPatch {

    //Lists forms w/ NPC's.
    HashMap<FormID, RACE> raceList = new HashMap<>();
    //Lists all the base NPC's from the Skyrim.esm, so base data isn't considered changed at any point.
    final HashMap<FormID, RACE> baseRaceList = new HashMap<>();
    ArrayList<RACE> deepCopiedList = new ArrayList<>();
    //Grab reference to the mods map.
    HashMap<Mod, ModTags> mods;
    //Storage for modTags.
    ModTags modTags;
    //Full logging boolean for neatness in below code.
    boolean fullLogging;
    //Data locking map.
    HashMap<String, Boolean> dataLock;
    //Storage mod used in counter.
    Mod temp;

    //Constructor for pulling mod tags.
    public RaceMergerPatch(HashMap mods) {
        this.mods = mods;
    }

    public void mergeRaces() {
        RACE newRace; //Storage NPC used to reference new with old.

        //Set full logging.
        fullLogging = SkyBash.save.getBool(SkyBashSaveFile.GUISettings.FULL_LOGGING);

        SPProgressBarPlug.progress.setStatus("Processing Base Races");
        SPProgressBarPlug.progress.incrementBar();

        for (RACE r : SPGlobal.getDB().getMod(0).getRaces()) {
            //Store the list of base NPC's.
            baseRaceList.put(r.getForm(), r);
            SPGlobal.log("Adding to BASE RACE LIST: ", r.getEDID());
        }

        //Iterate through mod lists.
        for (int i = 1; i < SPGlobal.getDB().numMods(); i++) {
            temp = SPGlobal.getDB().getMod(i);
            SPProgressBarPlug.progress.setStatus("Processing Races from " + temp.getName());
            SPProgressBarPlug.progress.incrementBar();

            //Get the mod tags for the merger.
            if (mods != null && !mods.isEmpty() && mods.containsKey(temp)) {
                modTags = mods.get(temp);
            } else {
                modTags = new ModTags(true);
            }

            //For other mods, cross and merge data and add to the global patch.
            if (!modTags.Deactivate) {
                for (RACE r : temp.getRaces()) {
                    if (!raceList.containsKey(r.getForm())) {
                        raceList.put(r.getForm(), r);
                    } else {
                        newRace = raceList.get(r.getForm());

                        //Start the NPC merger.
                        SPGlobal.log("NPC MERGER: ", "Merging NPC " + newRace.getEDID() + " from " + temp.getName());
                        newRace = mergeRaces(newRace, r);

                        //Add the edited NPC to the map, replacing the old.
                        raceList.put(r.getForm(), newRace);

                        //Add the NPC to the patch.  If it's edited later, it'll override.
                        SPGlobal.getGlobalPatch().addRecord(newRace);
                    }
                }
            }
        }
    }

    private RACE mergeRaces(RACE r, RACE newRace) {

        //Grabs the base NPC from the list, and copies it below to retain the reference data.
        RACE tempRace;
        if (baseRaceList.containsKey(r.getForm())) {
            tempRace = baseRaceList.get(r.getForm());
        } else {
            tempRace = r;
        }

        //Initializes it to the temp NPC.
        RACE baseRace = tempRace;

        //Holder for array lists of objects.
        ArrayList tempList;
        ArrayList tempListR;
        ArrayList tempListBase;

        //Deep copies the NPC so the base NPC is retained.
        if (!deepCopiedList.contains(tempRace)) {
            baseRace = (RACE) Ln.deepCopy(tempRace);
            baseRaceList.put(baseRace.getForm(), baseRace);
            deepCopiedList.add(baseRace);
        }

        if (modTags.keywords) {
            tempList = newRace.keywords.getKeywordRefs();
            tempListR = r.keywords.getKeywordRefs();
            tempListBase = baseRace.keywords.getKeywordRefs();
            for (int i = 0; i < tempListBase.size(); i++) {
                if (!tempList.contains((FormID) tempListBase.get(i))) {
                    r.keywords.removeKeywordRef((FormID) tempListBase.get(i));
                    if (fullLogging) {
                        SPGlobal.log("Keywords: ", "Removed Keyword " + ((FormID) tempListBase.get(i)) + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
            for (int i = 0; i < tempList.size(); i++) {
                if (!tempListR.contains((FormID) tempList.get(i)) && !tempListBase.contains((FormID) tempList.get(i))) {
                    r.keywords.addKeywordRef((FormID) tempList.get(i));
                    if (fullLogging) {
                        SPGlobal.log("Keywords: ", "Merged keyword " + ((FormID) tempList.get(i)).getFormStr() + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.RBody) {
            tempList = newRace.getEquipSlots();
            tempListR = r.getEquipSlots();
            tempListBase = baseRace.getEquipSlots();
            for (int i = 0; i < tempListBase.size(); i++) {
                if (!tempList.contains((FormID) tempListBase.get(i))) {
                    r.removeEquipSlot((FormID) tempListBase.get(i));
                    if (fullLogging) {
                        SPGlobal.log("Equip Slots: ", "Removed Equip Slot " + ((FormID) tempListBase.get(i)) + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
            for (int i = 0; i < tempList.size(); i++) {
                if (!tempListR.contains((FormID) tempList.get(i)) && !tempListBase.contains((FormID) tempList.get(i))) {
                    r.addEquipSlot((FormID) tempList.get(i));
                    if (fullLogging) {
                        SPGlobal.log("EquipSlots: ", "Merged Equip Slot " + ((FormID) tempList.get(i)).getFormStr() + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.RBody) {
            for (BodyPart b : BodyPart.values()) {
                if (r.bodyTemplate.get(b) != newRace.bodyTemplate.get(b) && newRace.bodyTemplate.get(b) != baseRace.bodyTemplate.get(b)) {
                    r.bodyTemplate.set(b, newRace.bodyTemplate.get(b));
                    if (fullLogging) {
                        SPGlobal.log("BodyTemplate: ", "Merged Body Part " + b.toString() + " to " + r.bodyTemplate.get(b) + " for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.RBody) {
            for (BodyTemplateFlag b : BodyTemplateFlag.values()) {
                if (r.bodyTemplate.get(b) != newRace.bodyTemplate.get(b) && newRace.bodyTemplate.get(b) != baseRace.bodyTemplate.get(b)) {
                    r.bodyTemplate.set(b, newRace.bodyTemplate.get(b));
                    if (fullLogging) {
                        SPGlobal.log("BodyTemplate: ", "Merged Body Template Flag " + b.toString() + " to " + r.bodyTemplate.get(b) + " for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.RBody) {
            if (r.bodyTemplate.getArmorType() != newRace.bodyTemplate.getArmorType() && newRace.bodyTemplate.getArmorType() != baseRace.bodyTemplate.getArmorType()) {
                r.bodyTemplate.setArmorType(newRace.bodyTemplate.getArmorType());
                if (fullLogging) {
                    SPGlobal.log("BodyTemplate: ", "Merged ArmorType to " + r.bodyTemplate.getArmorType() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RBody) {
            if (r.getDecapHeadPart(Gender.MALE) != newRace.getDecapHeadPart(Gender.MALE) && newRace.getDecapHeadPart(Gender.MALE) != baseRace.getDecapHeadPart(Gender.MALE)) {
                r.setDecapHeadPart(Gender.MALE, newRace.getDecapHeadPart(Gender.MALE));
                if (fullLogging) {
                    SPGlobal.log("Decapitation: ", "Merged Decapitated Head Part for Males to " + r.getDecapHeadPart(Gender.MALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RBody) {
            if (r.getDecapHeadPart(Gender.FEMALE) != newRace.getDecapHeadPart(Gender.FEMALE) && newRace.getDecapHeadPart(Gender.FEMALE) != baseRace.getDecapHeadPart(Gender.FEMALE)) {
                r.setDecapHeadPart(Gender.FEMALE, newRace.getDecapHeadPart(Gender.FEMALE));
                if (fullLogging) {
                    SPGlobal.log("Decapitation: ", "Merged Decapitated Head Part for Females to " + r.getDecapHeadPart(Gender.FEMALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.BodyM) {
            if (r.getModel(Gender.MALE) != null && newRace.getModel(Gender.MALE) != null) {
                if (!r.getLightingModels(Gender.MALE).equals(newRace.getLightingModels(Gender.MALE)) && !newRace.getLightingModels(Gender.MALE).equals(baseRace.getLightingModels(Gender.MALE))) {
                    r.setLightingModels(Gender.MALE, newRace.getLightingModels(Gender.MALE));
                    if (fullLogging) {
                        SPGlobal.log("Sounds: ", "Merged Lighting Model for Males to --" + r.getLightingModels(Gender.MALE) + "-- for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.BodyF) {
            if (r.getModel(Gender.FEMALE) != null && newRace.getModel(Gender.FEMALE) != null) {
                if (!r.getLightingModels(Gender.FEMALE).equals(newRace.getLightingModels(Gender.FEMALE)) && !newRace.getLightingModels(Gender.FEMALE).equals(baseRace.getLightingModels(Gender.FEMALE))) {
                    r.setLightingModels(Gender.FEMALE, newRace.getLightingModels(Gender.FEMALE));
                    if (fullLogging) {
                        SPGlobal.log("Sounds: ", "Merged Lighting Model for Females to --" + r.getLightingModels(Gender.FEMALE) + "-- for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.BodyM) {
            if (r.getModel(Gender.MALE) != null && newRace.getModel(Gender.MALE) != null) {
                if (!r.getPhysicsModels(Gender.MALE).equals(newRace.getPhysicsModels(Gender.MALE)) && !newRace.getPhysicsModels(Gender.MALE).equals(baseRace.getPhysicsModels(Gender.MALE))) {
                    r.setPhysicsModels(Gender.MALE, newRace.getPhysicsModels(Gender.MALE));
                    if (fullLogging) {
                        SPGlobal.log("Sounds: ", "Merged Physics Model for Males to --" + r.getPhysicsModels(Gender.MALE) + "-- for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.BodyF) {
            if (r.getModel(Gender.FEMALE) != null && newRace.getModel(Gender.FEMALE) != null) {
                if (!r.getPhysicsModels(Gender.FEMALE).equals(newRace.getPhysicsModels(Gender.FEMALE)) && !newRace.getPhysicsModels(Gender.FEMALE).equals(baseRace.getPhysicsModels(Gender.FEMALE))) {
                    r.setPhysicsModels(Gender.FEMALE, newRace.getPhysicsModels(Gender.FEMALE));
                    if (fullLogging) {
                        SPGlobal.log("Sounds: ", "Merged Physics Model for Females to --" + r.getPhysicsModels(Gender.FEMALE) + "-- for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.Hair) {
            if (r.getHairColor(Gender.MALE) != newRace.getHairColor(Gender.MALE) && newRace.getHairColor(Gender.MALE) != baseRace.getHairColor(Gender.MALE)) {
                r.setHairColor(Gender.MALE, newRace.getHairColor(Gender.MALE));
                if (fullLogging) {
                    SPGlobal.log("Hair Color: ", "Merged Hair Color for Males to " + r.getHairColor(Gender.MALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.Hair) {
            if (r.getHairColor(Gender.FEMALE) != newRace.getHairColor(Gender.FEMALE) && newRace.getHairColor(Gender.FEMALE) != baseRace.getHairColor(Gender.FEMALE)) {
                r.setHairColor(Gender.FEMALE, newRace.getHairColor(Gender.FEMALE));
                if (fullLogging) {
                    SPGlobal.log("Hair Color: ", "Merged Hair Color for Females to " + r.getHairColor(Gender.FEMALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RStatsM) {
            if (r.getHeight(Gender.MALE) != newRace.getHeight(Gender.MALE) && newRace.getHeight(Gender.MALE) != baseRace.getHeight(Gender.MALE)) {
                r.setHeight(Gender.MALE, newRace.getHeight(Gender.MALE));
                if (fullLogging) {
                    SPGlobal.log("Height: ", "Merged Height for Males to " + r.getHeight(Gender.MALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RStatsF) {
            if (r.getHeight(Gender.FEMALE) != newRace.getHeight(Gender.FEMALE) && newRace.getHeight(Gender.FEMALE) != baseRace.getHeight(Gender.FEMALE)) {
                r.setHeight(Gender.FEMALE, newRace.getHeight(Gender.FEMALE));
                if (fullLogging) {
                    SPGlobal.log("Height: ", "Merged Height for Females to " + r.getHeight(Gender.FEMALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.BodyM) {
            if (r.getModel(Gender.MALE) != null && newRace.getModel(Gender.MALE) != null) {
                if (!r.getModel(Gender.MALE).equals(newRace.getModel(Gender.MALE)) && !newRace.getModel(Gender.MALE).equals(baseRace.getModel(Gender.MALE))) {
                    r.setModel(Gender.MALE, newRace.getModel(Gender.MALE));
                    if (fullLogging) {
                        SPGlobal.log("Model: ", "Merged Model for Males to " + r.getDecapHeadPart(Gender.MALE) + " for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.BodyF) {
            if (r.getModel(Gender.FEMALE) != null && newRace.getModel(Gender.FEMALE) != null) {
                if (!r.getModel(Gender.FEMALE).equals(newRace.getModel(Gender.FEMALE)) && !newRace.getModel(Gender.FEMALE).equals(baseRace.getModel(Gender.FEMALE))) {
                    r.setModel(Gender.FEMALE, newRace.getModel(Gender.FEMALE));
                    if (fullLogging) {
                        SPGlobal.log("Model: ", "Merged Model for Females to " + r.getDecapHeadPart(Gender.FEMALE) + " for "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (modTags.VoiceM) {
            if (r.getVoiceType(Gender.MALE) != newRace.getVoiceType(Gender.MALE) && newRace.getVoiceType(Gender.MALE) != baseRace.getVoiceType(Gender.MALE)) {
                r.setVoiceType(Gender.MALE, newRace.getVoiceType(Gender.MALE));
                if (fullLogging) {
                    SPGlobal.log("Voices: ", "Merged Voice Type for Males to " + r.getVoiceType(Gender.MALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.VoiceF) {
            if (r.getVoiceType(Gender.FEMALE) != newRace.getVoiceType(Gender.FEMALE) && newRace.getVoiceType(Gender.FEMALE) != baseRace.getVoiceType(Gender.FEMALE)) {
                r.setVoiceType(Gender.FEMALE, newRace.getVoiceType(Gender.FEMALE));
                if (fullLogging) {
                    SPGlobal.log("Voices: ", "Merged Voice Type for Females to " + r.getVoiceType(Gender.FEMALE) + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RBody) {
            if (r.getWornArmor() != newRace.getWornArmor() && newRace.getWornArmor() != baseRace.getWornArmor()) {
                r.setWornArmor(newRace.getWornArmor());
                if (fullLogging) {
                    SPGlobal.log("Armor: ", "Merged Worn Armor to " + r.getWornArmor() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.RSpells) {
            tempList = newRace.getSpells();
            tempListR = r.getSpells();
            tempListBase = baseRace.getSpells();
            for (int i = 0; i < tempListBase.size(); i++) {
                if (!tempList.contains((FormID) tempListBase.get(i))) {
                    r.removeSpell((FormID) tempListBase.get(i));
                    if (fullLogging) {
                        SPGlobal.log("Spells: ", "Removed Spell " + ((FormID) tempListBase.get(i)) + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
            for (int i = 0; i < tempList.size(); i++) {
                if (!tempListBase.contains((FormID) tempList.get(i)) && !tempListR.contains((FormID) tempList.get(i))) {
                    r.addSpell((FormID) tempList.get(i));
                    if (fullLogging) {
                        SPGlobal.log("Spells: ", "Merged Spell " + (FormID) tempList.get(i) + " to "
                                + newRace.getEDID() + " from Mod " + temp.getName());
                    }
                }
            }
        }

        if (r.getAccelerationRate() != newRace.getAccelerationRate() && newRace.getAccelerationRate() != baseRace.getAccelerationRate()) {
            r.setAccelerationRate(newRace.getAccelerationRate());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Acceleration Rate to " + r.getWornArmor() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (r.getAimAngleTolerance() != newRace.getAimAngleTolerance() && newRace.getAimAngleTolerance() != baseRace.getAimAngleTolerance()) {
            r.setAimAngleTolerance(newRace.getAimAngleTolerance());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Aim Angle Tolerance to " + r.getAimAngleTolerance() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (r.getAngularAcceleration() != newRace.getAngularAcceleration() && newRace.getAngularAcceleration() != baseRace.getAngularAcceleration()) {
            r.setAngularAcceleration(newRace.getAngularAcceleration());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Angular Acceleration to " + r.getAngularAcceleration() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }



        if (r.getAngularTolerance() != newRace.getAngularTolerance() && newRace.getAngularTolerance() != baseRace.getAngularTolerance()) {
            r.setAngularTolerance(newRace.getAngularTolerance());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Angular Tolerance to " + r.getAngularTolerance() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }



        if (r.getBaseCarryWeight() != newRace.getBaseCarryWeight() && newRace.getBaseCarryWeight() != baseRace.getBaseCarryWeight()) {
            r.setBaseCarryWeight(newRace.getBaseCarryWeight());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Base Carry Weight to " + r.getBaseCarryWeight() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (r.getBaseMass() != newRace.getBaseMass() && newRace.getBaseMass() != baseRace.getBaseMass()) {
            r.setBaseMass(newRace.getBaseMass());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Base Mass to " + r.getBaseMass() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (modTags.Sounds) {
            if (r.getCloseLootSound() != newRace.getCloseLootSound() && newRace.getCloseLootSound() != baseRace.getCloseLootSound()) {
                r.setCloseLootSound(newRace.getCloseLootSound());
                if (fullLogging) {
                    SPGlobal.log("Sounds: ", "Merged Close Loot Sound to " + r.getCloseLootSound() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.Graphics) {
            if (r.getDecapitationFX() != newRace.getDecapitationFX() && newRace.getDecapitationFX() != baseRace.getDecapitationFX()) {
                r.setDecapitationFX(newRace.getDecapitationFX());
                if (fullLogging) {
                    SPGlobal.log("Graphics: ", "Merged Decapitation FX to " + r.getDecapitationFX() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (r.getDecelerationRate() != newRace.getDecelerationRate() && newRace.getDecelerationRate() != baseRace.getDecelerationRate()) {
            r.setDecelerationRate(newRace.getDecelerationRate());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Deceleration Rate to " + r.getDecelerationRate() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (modTags.BodySizeF) {
            if (r.getFemaleWeight() != newRace.getFemaleWeight() && newRace.getFemaleWeight() != baseRace.getFemaleWeight()) {
                r.setFemaleWeight(newRace.getFemaleWeight());
                if (fullLogging) {
                    SPGlobal.log("Weight: ", "Merged Weight for Females to " + r.getFemaleWeight() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }


        if (r.getFlightRadius() != newRace.getFlightRadius() && newRace.getFlightRadius() != baseRace.getFlightRadius()) {
            r.setFlightRadius(newRace.getFlightRadius());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Flight Radius to " + r.getFlightRadius() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (r.getHealthRegen() != newRace.getHealthRegen() && newRace.getHealthRegen() != baseRace.getHealthRegen()) {
            r.setHealthRegen(newRace.getHealthRegen());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Health Regen to " + r.getHealthRegen() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (modTags.Graphics) {
            if (r.getImpactDataSet() != newRace.getImpactDataSet() && newRace.getImpactDataSet() != baseRace.getImpactDataSet()) {
                r.setImpactDataSet(newRace.getImpactDataSet());
                if (fullLogging) {
                    SPGlobal.log("Graphics: ", "Merged Impact Data Set to " + r.getImpactDataSet() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (r.getInjuredHealthPct() != newRace.getInjuredHealthPct() && newRace.getInjuredHealthPct() != baseRace.getInjuredHealthPct()) {
            r.setInjuredHealthPct(newRace.getInjuredHealthPct());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Injured Health Percentage to " + r.getInjuredHealthPct() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }



        if (r.getMagickaRegen() != newRace.getMagickaRegen() && newRace.getMagickaRegen() != baseRace.getMagickaRegen()) {
            r.setMagickaRegen(newRace.getMagickaRegen());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Magicka Regen to " + r.getMagickaRegen() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (modTags.BodySizeM) {
            if (r.getMaleWeight() != newRace.getMaleWeight() && newRace.getMaleWeight() != baseRace.getMaleWeight()) {
                r.setMaleWeight(newRace.getMaleWeight());
                if (fullLogging) {
                    SPGlobal.log("Weight: ", "Merged Weight for Males to " + r.getMaleWeight() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }


        if (r.getMaterialType() != newRace.getMaterialType() && newRace.getMaterialType() != baseRace.getMaterialType()) {
            r.setMaterialType(newRace.getMaterialType());
            if (fullLogging) {
                SPGlobal.log("Material: ", "Merged Material Type to " + r.getMaterialType() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (modTags.names) {
            if (!r.getName().equals(newRace.getName()) && !newRace.getName().equals(baseRace.getName())) {
                r.setName(newRace.getName());
                if (fullLogging) {
                    SPGlobal.log("Names: ", "Merged name to " + r.getName() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (modTags.Sounds) {
            if (r.getOpenLootSound() != newRace.getOpenLootSound() && newRace.getOpenLootSound() != baseRace.getOpenLootSound()) {
                r.setOpenLootSound(newRace.getOpenLootSound());
                if (fullLogging) {
                    SPGlobal.log("Sounds: ", "Merged Open Loot Sound to " + r.getOpenLootSound() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (r.getSize() != newRace.getSize() && newRace.getSize() != baseRace.getSize()) {
            r.setSize(newRace.getSize());
            if (fullLogging) {
                SPGlobal.log("Size: ", "Merged Size to " + r.getSize().toString() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getStaminaRegen() != newRace.getStaminaRegen() && newRace.getStaminaRegen() != baseRace.getStaminaRegen()) {
            r.setStaminaRegen(newRace.getStaminaRegen());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Stamina Regen to " + r.getStaminaRegen() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }



        if (r.getStartingHealth() != newRace.getStartingHealth() && newRace.getStartingHealth() != baseRace.getStartingHealth()) {
            r.setStartingHealth(newRace.getStartingHealth());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Starting Health to " + r.getStartingHealth() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getStartingMagicka() != newRace.getStartingMagicka() && newRace.getStartingMagicka() != baseRace.getStartingMagicka()) {
            r.setStartingMagicka(newRace.getStartingMagicka());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Starting Magicka to " + r.getStartingMagicka() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getStartingStamina() != newRace.getStartingStamina() && newRace.getStartingStamina() != baseRace.getStartingStamina()) {
            r.setStartingStamina(newRace.getStartingStamina());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Starting Stamina to " + r.getStartingStamina() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getUnarmedDamage() != newRace.getUnarmedDamage() && newRace.getUnarmedDamage() != baseRace.getUnarmedDamage()) {
            r.setUnarmedDamage(newRace.getUnarmedDamage());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Unarmed Damage to " + r.getUnarmedDamage() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }


        if (modTags.RBody) {
            if (r.getUnarmedEquipSlot() != newRace.getUnarmedEquipSlot() && newRace.getUnarmedEquipSlot() != baseRace.getUnarmedEquipSlot()) {
                r.setUnarmedEquipSlot(newRace.getUnarmedEquipSlot());
                if (fullLogging) {
                    SPGlobal.log("BodyTemplate: ", "Merged Unarmed Equip Slot to " + r.getUnarmedEquipSlot() + " for "
                            + newRace.getEDID() + " from Mod " + temp.getName());
                }
            }
        }

        if (r.getUnarmedReach() != newRace.getUnarmedReach() && newRace.getUnarmedReach() != baseRace.getUnarmedReach()) {
            r.setUnarmedReach(newRace.getUnarmedReach());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Unarmed Reach to " + r.getWornArmor() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getPNAM() != newRace.getPNAM() && newRace.getPNAM() != baseRace.getPNAM()) {
            r.setPNAM(newRace.getPNAM());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged PNAM for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getTINL() != newRace.getTINL() && newRace.getTINL() != baseRace.getTINL()) {
            r.setTINL(newRace.getTINL());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged TINL for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getUNAM() != newRace.getUNAM() && newRace.getUNAM() != baseRace.getUNAM()) {
            r.setUNAM(newRace.getUNAM());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged UNAM for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getVNAM() != newRace.getVNAM() && newRace.getVNAM() != baseRace.getVNAM()) {
            r.setVNAM(newRace.getVNAM());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged VNAM for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getWKMV() != newRace.getWKMV() && newRace.getWKMV() != baseRace.getWKMV()) {
            r.setWKMV(newRace.getWKMV());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged WKMV to " + r.getWKMV() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getRNMV() != newRace.getRNMV() && newRace.getRNMV() != baseRace.getRNMV()) {
            r.setRNMV(newRace.getRNMV());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged RNMV to " + r.getRNMV() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getSNMV() != newRace.getSNMV() && newRace.getSNMV() != baseRace.getSNMV()) {
            r.setSNMV(newRace.getSNMV());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged SNMV to " + r.getSNMV() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getSWMV() != newRace.getSWMV() && newRace.getSWMV() != baseRace.getSWMV()) {
            r.setSWMV(newRace.getSWMV());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged SWMV to " + r.getSWMV() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFLMV() != newRace.getFLMV() && newRace.getFLMV() != baseRace.getFLMV()) {
            r.setFLMV(newRace.getFLMV());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged FLMV to " + r.getFLMV() + " for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getSkills() != newRace.getSkills() && newRace.getSkills() != baseRace.getSkills()) {
            r.setSkills(newRace.getSkills());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Skills for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFluff2() != newRace.getFluff2() && newRace.getFluff2() != baseRace.getFluff2()) {
            r.setFluff2(newRace.getFluff2());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Extraneous/Unknown Data for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFluff3() != newRace.getFluff3() && newRace.getFluff3() != baseRace.getFluff3()) {
            r.setFluff3(newRace.getFluff3());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Extraneous/Unknown Data for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFluff4() != newRace.getFluff4() && newRace.getFluff4() != baseRace.getFluff4()) {
            r.setFluff4(newRace.getFluff4());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Extraneous/Unknown Data for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFluff5() != newRace.getFluff5() && newRace.getFluff5() != baseRace.getFluff5()) {
            r.setFluff5(newRace.getFluff5());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Extraneous/Unknown Data for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        if (r.getFluff6() != newRace.getFluff6() && newRace.getFluff6() != baseRace.getFluff6()) {
            r.setFluff6(newRace.getFluff6());
            if (fullLogging) {
                SPGlobal.log("Stats: ", "Merged Extraneous/Unknown Data for "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        tempList = newRace.getMTNMs();
        r.clearMTNMs();
        for (int i = 0; i < tempList.size(); i++) {
            r.addMTNM((String) tempList.get(i));
            if (fullLogging) {
                SPGlobal.log("MTNM: ", "Merged MTNM --" + tempList.get(i) + "-- to "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        tempList = newRace.getNAMEs();
        r.clearNAMEs();
        for (int i = 0; i < tempList.size(); i++) {
            r.addNAME((String) tempList.get(i));
            if (fullLogging) {
                SPGlobal.log("NAME: ", "Merged NAME --" + tempList.get(i) + "-- to "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        tempList = newRace.getPHTN();
        r.clearPHTN();
        for (int i = 0; i < tempList.size(); i++) {
            r.addPHTN((String) tempList.get(i));
            if (fullLogging) {
                SPGlobal.log("PHTN: ", "Merged PHTN --" + tempList.get(i) + "-- to "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        tempList = newRace.getPHWT();
        r.clearPHWT();
        for (int i = 0; i < tempList.size(); i++) {
            r.addPHWT((byte[]) tempList.get(i));
            if (fullLogging) {
                SPGlobal.log("PHTN: ", "Merged PHWT to "
                        + newRace.getEDID() + " from Mod " + temp.getName());
            }
        }

        return r;

    }
}
